#ifndef __M_MATCH_H__
#define __M_MATCH_H__
#include "util.hpp"
#include <list>
#include <thread>
#include <mutex>
#include <condition_variable>

template <class T>
class match_queue
{
private:
    std::list<T> _list;
    std::mutex _mutex;
    std::condition_variable _con;

public:
    // 入队，唤醒
    void push(T &data)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _list.push_back(data);
        _con.notify_all();
    }

    // 出队
    T pop()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        if (_list.empty())
        {
            return T();
        }
        T ret = _list.front();
        _list.pop_front();
        return ret;
    }

    // 移除
    void remove(const T &data)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _list.remove(data);
    }

    // 阻塞
    void wait()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _con.wait(lock);
    }

    // 等待人数
    int size()
    {
        return _list.size();
    }
    // 是否有人等待
    bool empty()
    {
        return _list.empty();
    }
};

class matcher
{
private:
    match_queue<uint64_t> _q_normal; // 匹配队列1
    match_queue<uint64_t> _q_high;   // 匹配队列2
    match_queue<uint64_t> _q_super;  // 匹配队列3
    std::thread _th_normal;          // 匹配1线程
    std::thread _th_high;            // 匹配2线程
    std::thread _th_super;           // 匹配3线程

    room_manager *_rManager;   // 房间管理句柄
    user_table *_uTable;       // 用户信息管理句柄
    online_manager *_oManager; // 线上用户管理句柄

private: // 用于匹配不同用户的线程
    void handle_match(match_queue<uint64_t> &matchQueue)
    {
        while (1)
        {
            // 1、判断队列中的人是否 大于2，小于2 -> 阻塞
            if (matchQueue.size() < 2)
            {
                matchQueue.wait();
            }
            // 2、出队2个玩家
            uint64_t uid1, uid2;
            uid1 = matchQueue.pop();
            if (uid1 == uint64_t())
                continue;
            uid2 = matchQueue.pop();
            if (uid2 == uint64_t())
            {
                this->add(uid1);
                continue;
            }

            // 3、判断2个玩家的状态是否能满足开始游戏的条件（如是否在大厅）把对方重新纳入，匹配队列
            websocket_server::connection_ptr conn1 = _oManager->get_conn_from_hall(uid1);
            if (conn1.get() == nullptr)
            {              
                this->add(uid2);
                continue;
            }
            websocket_server::connection_ptr conn2 = _oManager->get_conn_from_hall(uid2);
            if (conn2.get() == nullptr)
            {
                this->add(uid1);
                continue;
            }
            // 4、创建房间，并将2个玩家添加入新房间
            room_ptr newRoomPtr = _rManager->create_room(uid1, uid2);
            if (newRoomPtr.get() == nullptr)
            {
                this->add(uid1);
                this->add(uid2);
                continue;
            }
            // 5、给2个玩家进行响应，可以开始游戏
            Json::Value resp;
            resp["optype"] = "match_success";
            resp["result"] = true;
            std::string body;
            json_util::serialize(resp, body);
            conn1->send(body);
            conn2->send(body);
        }
    }

    void th_normal_entry()
    {
        return handle_match(_q_normal);
    }
    void th_high_entry()
    {
        return handle_match(_q_high);
    }
    void th_super_entry()
    {
        return handle_match(_q_super);
    }

public: // 默认函数
    matcher(room_manager *rManager, user_table *uTable, online_manager *oManager) : 
    _rManager(rManager), _uTable(uTable), _oManager(oManager),
    _th_normal(std::thread(&matcher::th_normal_entry, this)),
    _th_high(std::thread(&matcher::th_high_entry, this)),
    _th_super(std::thread(&matcher::th_super_entry, this))
    {
        DLOG("游戏匹配模块初始化完成");
    }



public:
    // 根据玩家分数添加到对应匹配队列
    bool add(uint64_t uid)
    {
        Json::Value user;
        bool ret = _uTable->select_by_id(uid, user);
        if (ret == false)
        {
            DLOG("获取玩家：%d,信息失败！", uid);
            return false;
        }

        int curUserScore = user["score"].asInt();
        // 进入对应分数的队列
        if (curUserScore < 2000)
        {
            _q_normal.push(uid);
        }
        else if (curUserScore >= 2000 && curUserScore < 3000)
        {
            _q_high.push(uid);
        }
        else if (curUserScore >= 3000)
        {
            _q_super.push(uid);
        }

        return true;
    }

    // 从匹配队列移除玩家
    bool remove(uint64_t uid)
    {
        Json::Value user;
        bool ret = _uTable->select_by_id(uid, user);
        if (ret == false)
        {
            DLOG("获取玩家：%d,信息失败！", uid);
            return false;
        }

        int curUserScore = user["score"].asInt();
        // 进入对应分数的队列
        if (curUserScore < 2000)
        {
            _q_normal.remove(uid);
        }
        else if (curUserScore >= 2000 && curUserScore < 3000)
        {
            _q_high.remove(uid);
        }
        else if (curUserScore >= 3000)
        {
            _q_super.remove(uid);
        }

        return true;
    }
};

#endif